package com.alcatel_lucent.osp.interceptors;

import com.alcatel_lucent.osp.action.LoginAction;
import com.alcatel_lucent.osp.action.UserContext;
import com.alcatel_lucent.osp.model.User;
import com.alcatel_lucent.osp.service.DaoService;
import com.opensymphony.xwork2.Action;
import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.AbstractInterceptor;
import net.sf.json.JSONObject;
import org.apache.commons.lang3.StringUtils;
import org.apache.struts2.ServletActionContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.util.DigestUtils;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.*;

@SuppressWarnings("serial")
public class AuthorizationInterceptor extends AbstractInterceptor {

    private static Logger log = LoggerFactory.getLogger(AuthorizationInterceptor.class);
    public static final String COOKIE_REMEMBER_KEY = "osp.cookie.rememberme";
    public static final String COOKIE_REMEMBER_KEY_SEPARATOR = "==";
    public static final String LAST_ACCESSED_URL_KEY = "lastAccessedURL";

    private DaoService daoService;

    public void setDaoService(DaoService daoService) {
        this.daoService = daoService;
    }

    @Value("${httpsPort}")
    private String httpsPort;


    private List<String> excludePatterns = Arrays.asList("/login");

    @Override
    public String intercept(ActionInvocation invocation) throws Exception {
        ActionContext ctx = ActionContext.getContext();
        Map<String, Object> session = ctx.getSession();
        final Object action = invocation.getAction();

        HttpServletRequest request = (HttpServletRequest) ctx.get(ServletActionContext.HTTP_REQUEST);
        HttpServletResponse response = (HttpServletResponse) ctx.get(ServletActionContext.HTTP_RESPONSE);

        UserContext uc = (UserContext) session.get(UserContext.SESSION_USER_CONTEXT);
        String uri = request.getRequestURI();
        uri = uri.replace(request.getContextPath(), "");


        log.info("request uri={}, url={}, uc={}, session id={}", new Object[]{uri, request.getRequestURL(), uc, request.getSession().getId()});

        if (excludePatterns.contains(uri)) return invocation.invoke();
        /**
         * View chrome cookies
         * chrome://settings/cookies/
         * */

        if (uc == null) {
            if (isUserRemembered(request)) {
                return invocation.invoke();
            }
            String basePath = "https://" + request.getServerName() + ":" + httpsPort + request.getContextPath() + "/";
            //remember last requested uri and parameters before jump

            session.put(LAST_ACCESSED_URL_KEY, uri + params2String(request));
            response.sendRedirect(basePath + "login.jsp");
            return Action.NONE;
        }

        log.info("[Action] " + uc.getUser().getCsl() + " - " + action.getClass().getSimpleName());
        UserContext.setUserContext(uc);
        String result = invocation.invoke();
        UserContext.removeUserContext();
        return result;

    }

    private String params2String(HttpServletRequest request) {
        StringBuilder sb = new StringBuilder();
        Enumeration<String> paramNames = request.getParameterNames();
        boolean isFirst = true;
        while(paramNames.hasMoreElements()){
            sb.append(isFirst ? "?" : "&");
            String name = paramNames.nextElement();
            sb.append(name).append("=").append(request.getParameter(name));
            isFirst = false;
        }
        return sb.toString();
    }

    /**
     * Check if user is remembered
     */
    private boolean isUserRemembered(HttpServletRequest request) throws UnsupportedEncodingException {

        Cookie cookie = findCookie(COOKIE_REMEMBER_KEY, request.getContextPath(), request.getCookies());
        if (null == cookie || StringUtils.isBlank(cookie.getValue())) return false;
        String[] tokens = URLDecoder.decode(cookie.getValue(), "UTF-8").split(COOKIE_REMEMBER_KEY_SEPARATOR);
        if (tokens.length < 2) return false;

        String csl = tokens[0];
        String cookieDigest = tokens[1];
        String digest = DigestUtils.md5DigestAsHex((csl + LoginAction.OSP_SALT).getBytes("utf-8"));

        if (!cookieDigest.equals(digest)) return false;

        User user = (User) daoService.retrieveOne("from User where csl = :csl", JSONObject.fromObject(String.format("{'csl': '%s'}", csl)), new String[]{"categories"});
        if (null == user) return false;
        TimeZone clientTimeZone = null;
        if (tokens.length > 2) {
            clientTimeZone = new SimpleTimeZone(Integer.parseInt(tokens[2]), user.getCsl() + "_TimeZone");
        }
        //add timezone to user context
        log.info("Retrieve user info from cookies {}, clientTimeZone={}", user.getCil(), clientTimeZone);

        UserContext userContext = new UserContext(ActionContext.getContext().getLocale(), user, clientTimeZone);
        UserContext.setUserContext(userContext);
        ActionContext.getContext().getSession().put(UserContext.SESSION_USER_CONTEXT, userContext);
        return true;
    }


    private Cookie findCookie(String name, String path, Cookie[] cookies) {
        if (null == cookies || cookies.length == 0) return null;
        for (Cookie cookie : cookies) {
            if (cookie.getName().equals(name) && (null == cookie.getPath() || cookie.getPath().equals(path))) {
                return cookie;
            }
        }
        return null;
    }

}
